[23 April 2025]
~ This article explains why I made a custom SSG for my website. Is it really needed or is it overkill? ~
SSG stands for Static Site Generator. As the name implies, it is used to generate static sites. It transforms one type of markup to another (in my case, from Markdown to HTML & CSS).
There are mainly two different ways in which a website is served to a user.
1. Client-side rendering
2. Server-side rendering
To break these terms down, imagine client-side rendering as going to one of those fancy Korean barbecue restaurants, where they hand you the things to make your food — the meat, sauces, pan, and the recipe. In this case, you get all the raw ingredients and the recipe, and you have to make or assemble the food yourself.
Whereas server-side rendering is like McDonald's, where the food is ready for consumption — just remove the wrapper and enjoy the meal. No assembly required.
So client-side rendering means that the server sends across a bunch of JavaScript or other kinds of 'raw material / ingredients' and the browser on the client side is responsible for 'assembling / converting' that to a viewable website.
And server-side rendering means the server has already 'built' the site and can just send the actual HTML page. The browser does not need to 'assemble' anything — it can just display it.
For me, it was important that all my blogs be written in Markdown, since it's literally like editing a text file. If I were to instead write my blogs in raw HTML, it would take more time and increase the friction to start writing a blog — which is bad in my case, as I already don't like to write a lot. So this also becomes a psychological advantage because I know that all I have to do is write a Markdown file — and it's easier to tell myself that.
I have made my SSG use a custom stylesheet for every Markdown file it builds to HTML. This ensures that, with no effort, all my blogs look uniform and follow the same design language and styling. This also means that if I want to change the style of my blogs tomorrow, I just need to update the stylesheet that my SSG references and re-build all the Markdown files.
I also realized that since all the images were being served from the Raspberry Pi, it was causing some performance and network bottlenecks. The solution was to isolate image serving and host all images on a storage bucket.
Now, if I didn't have an SSG, I’d have to manually upload each image to the bucket, wait for the upload, get the custom URL for that particular image, replace it in the HTML <img>
tag, and then assign image properties like width and height 😮💨. This quickly becomes a very tedious process if I have 2-3 images per blog. (Again, I'm trying to reduce friction and get myself to write as easily and seamlessly as possible)
Having an SSG of my own enables me to modify what happens to each part of my Markdown file while it's being built to HTML.
For example, whenever my SSG encounters an image in the Markdown file (denoted by something like 
), it does two very important things:
1. It takes the local image stored on my computer, uploads it to an R2 Storage Bucket, and replaces the local image path with the URL of the hosted image.
2. It assigns a default width and height to the images.
Since the RPi does a one-time build for each file, it's very important the code is written in such a way that resources are utilized well.
Assume I created a Markdown blog called article1.md
and built it. Then tomorrow I wake up and get motivated to write another blog, so I create article2.md
. Now, while deploying again, I don't want to rebuild article1.md
unless its contents have changed.
To ensure that I only rebuild the files that changed, I keep track of the hash value of each Markdown file in a JSON file — with the key as the filename and the value as the hash.
During build time, I re-generate the hash value for each Markdown file, and if it changed from before, or if the file is not present in the tracking JSON, only then do I rebuild that file.
Having only 1GB of RAM means I need to be very cautious with how much memory I use at any moment — since the Pi already runs this website, NGINX, Cloudflare tunneling services, and a Discord bot.
To not use too much memory while creating hashes, I split the Markdown files into chunks, generate hashes per chunk, and then combine and compare. This means only a smaller segment of the file is loaded into memory at a time. This becomes helpful if I have huge Markdown files.
Not sure, really. One thing that is yet to be implemented (which I will do soon) is syntax highlighting for my code fences.
Apart from this, I'm honestly not sure if I'll make any improvements — but who knows 😉.
I might host this as a PyPI package if I get a sudden burst of motivation (I've never hosted a Python package, and I want to try that out).
P.S: This image was auto-uploaded to R2, replaced during build, and I overrode default image dimensions since this image needed more length. So you're seeing the SSG in action.
To summarize: I created this not as a standalone, feature-rich SSG, but rather an SSG that was essential for the proper functioning of the blogs section of my website.
It let me cut down and automate a bunch of things I’d otherwise have to manually do.
The inspiration for this also comes from the amazing SSGs my seniors built:
- Anna - SSG in Go
- Saaru - SSG in Rust
Powered Not An SSG 😎